/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#include "stdafx.h"
#include <pgl/core/pgl.h>
#include <pgl/core/PGLImage.h>
#include <pgl/core/PGLRegion.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


PGL_IMPLEMENT_DYNCREATE(CPGLImage,CPGLObject);

#ifdef _DEBUG
void CPGLImage::Dump( CDumpContext& dc ) const
{
    // call base class function first
    CPGLObject::Dump( dc );

    // now do the stuff for our specific class
	dc << _T("--- CPGLImage ID ") << GetID() <<_T(" ---\n");
}

void CPGLImage::AssertValid() const
{
    // call inherited AssertValid first
    CPGLObject::AssertValid();
} 
#endif

LPCTSTR CPGLImage::SourceTypeToString(ESourceType eSourceType)
{
	switch(eSourceType)
	{
	case SourceTypeResource:
		return _T("resource");
	case SourceTypeBITMAPINFO:
		return _T("bitmapinfo");
	case SourceTypeFile:
		return _T("file");
	default:
		return _T("none");
	}
}

CPGLImage::ESourceType CPGLImage::StringToSourceType(LPCTSTR szSourceType)
{
	CString str=szSourceType;
	str.MakeLower();

	if (str == _T("resource"))
		return SourceTypeResource;
	else if (str == _T("bitmapinfo"))
		return SourceTypeBITMAPINFO;
	else  if (str == _T("file"))
		return SourceTypeFile;
	else 
		return SourceTypeNone;
}

void CPGLImage::SerializeXML(CPGLArchive& ar)
{
	static const TCHAR szTag[] = _T("CPGLImage");
	static CString str;
	DWORD dwIDResource;

	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());
	if(ar.IsStoring())
	{
		xml.AddChildElem(szTag);
		xml.AddChildAttrib(_T("Name"),GetName());
		xml.IntoElem();

			/////////////////////////////////////////////////////////
			// Adding base class
			CPGLObject::SerializeXML(ar);


			/////////////////////////////////////////////////////////////
			// Adding contribution
			m_area.SerializeXML(ar);
		
			switch(m_eSourceType)
			{
			case SourceTypeFile:
				xml.AddChildElem(_T("Source"), m_sFileName);
				break;
			case SourceTypeResource:
				xml.AddChildElemEx(_T("Source"), m_dwIDResource);
				break;
			case SourceTypeBITMAPINFO:
				break;
			default:
				xml.AddChildElem(_T("Source"));
			}

			xml.AddChildAttrib(_T("Type"), SourceTypeToString(m_eSourceType));

		xml.OutOfElem();
	}
	else
	{
		if  (!xml.FindChildElem(szTag))
				return;
		UnLoad();

		xml.IntoElem();

			/////////////////////////////////////////////////////////
			// loading base class
			CPGLObject::SerializeXML(ar);

			m_area.SerializeXML(ar);
			
			xml.ResetChildPos();
			if (xml.FindChildElem(_T("Source")))
			{
				str= xml.GetChildAttrib(_T("Type"));
				m_eSourceType = StringToSourceType(str);
				switch(m_eSourceType)
				{
				case SourceTypeFile:
					str=xml.GetChildData();
					Load(str, false);
					break;
				case SourceTypeResource:
					dwIDResource=xml.GetChildDataDWORD();
					Load(dwIDResource,NULL, false);
					break;
				}
			}

		xml.OutOfElem();

		PostUpdateExtent();
	}
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPGLImage::CPGLImage(LPCTSTR szFileName, bool bUpdateArea)
: m_pBitmap(NULL), m_dwIDResource(0), m_eSourceType(SourceTypeNone)
{
	using namespace gfxinterface;

	m_area.SetPosition(SPointD(0,0), CPGLCoord2D::Coord2DNormClip);
	m_area.SetAnchorType(CPGLArea2D::AnchorUpperLeft);
	Load(szFileName, bUpdateArea);
}

CPGLImage::~CPGLImage()
{
	UnLoad();
}

CPGLImage& CPGLImage::operator =(const CPGLImage& img)
{
	if (this != &img)
	{
		this->CPGLObject::operator =(img);

		UnLoad();

		m_area = img.m_area;
		m_sFileName = img.m_sFileName;
		m_dwIDResource = img.m_dwIDResource;
		m_eSourceType = img.m_eSourceType;
		if (m_eSourceType != SourceTypeNone)
		{
			ASSERT(img.m_pBitmap);
			ASSERT(img.m_pBitmap->GetLastStatus() == Gdiplus::Ok);
			m_pBitmap = img.m_pBitmap->Clone(0,0,img.m_pBitmap->GetWidth(), img.m_pBitmap->GetHeight(), img.m_pBitmap->GetPixelFormat());
		}

	}

	return *this;
}

int CPGLImage::GetWidth() const
{	
	using namespace Gdiplus;

	if (!m_pBitmap)
		return -1;
	if (m_pBitmap->GetLastStatus()!=Ok)
		return -1;

	return m_pBitmap->GetWidth();
}

int CPGLImage::GetHeight() const
{	
	using namespace Gdiplus;

	if (!m_pBitmap)
		return -1;
	if (m_pBitmap->GetLastStatus()!=Ok)
		return -1;

	return m_pBitmap->GetHeight();
}

/*
bool CPGLImage::SetActiveRect(const CPGLRectU& rActiveRect)
{
	using namespace Gdiplus;

	if (!m_pBitmap || 
		m_pBitmap->GetLastStatus()!=Ok)
		return false;

	CPGLRectU rBitmap(0,m_pBitmap->GetHeight(),m_pBitmap->GetWidth(),0);

	m_rActiveRect.Intersect(rActiveRect, rBitmap, false);

	return true;
}
*/

bool CPGLImage::Load(DWORD IDResource, HINSTANCE hInstance, bool bUpdateArea)
{
	using namespace Gdiplus;


	// first unload previous bitmap, if any
	UnLoad();

	m_eSourceType = SourceTypeResource;

	if (!IS_INTRESOURCE(IDResource))
		return false;

	m_dwIDResource = IDResource;

	if (!hInstance)
		hInstance = AfxGetInstanceHandle( );

	m_pBitmap = Bitmap::FromResource(hInstance, (LPCWSTR)MAKEINTRESOURCE(IDResource));

	if (m_pBitmap->GetLastStatus() != Ok)
	{
		UnLoad();
		return false;
	}

	if (bUpdateArea)
	{
		m_area.SetArea( m_pBitmap->GetWidth(), m_pBitmap->GetHeight(), CPGLArea2D::CoordBB );
	}

	return true;
}

bool CPGLImage::Load( const BITMAPINFO* gdiBitmapInfo, VOID* gdiBitmapData, bool bUpdateArea )
{
	using namespace Gdiplus;

	// first unload previous bitmap, if any
	UnLoad();

	m_eSourceType = SourceTypeBITMAPINFO;

	m_pBitmap = Bitmap::FromBITMAPINFO(gdiBitmapInfo, gdiBitmapData);

	if (m_pBitmap->GetLastStatus() != Ok)
	{
		UnLoad();
		return false;
	}

	if (bUpdateArea)
	{
		m_area.SetArea( m_pBitmap->GetWidth(), m_pBitmap->GetHeight(), CPGLArea2D::CoordBB );
	}

	return true;
}

bool CPGLImage::Load(LPCTSTR szFileName, bool bUpdateArea)
{
	USES_CONVERSION;
	using namespace Gdiplus;

	// first unload previous bitmap, if any
	UnLoad();

	m_eSourceType = SourceTypeFile;
	m_sFileName = szFileName;

	if (m_sFileName.IsEmpty())
		return false;

	/// loading file...
#ifndef _UNICODE
	m_pBitmap = Bitmap::FromFile(A2CW(szFileName));
#else
	m_pBitmap = Bitmap::FromFile(szFileName);
#endif

	if (m_pBitmap->GetLastStatus() != Ok)
	{
		UnLoad();
		return false;
	}

	if (bUpdateArea)
	{
		m_area.SetArea( m_pBitmap->GetWidth(), m_pBitmap->GetHeight(), CPGLArea2D::CoordBB );
	}

	return true;
}

bool CPGLImage::UnLoad()
{
	if (m_pBitmap)
	{
		delete m_pBitmap;
		m_pBitmap = NULL;
	}

	m_dwIDResource = 0;
	m_sFileName=_T("");
	m_eSourceType = SourceTypeNone;

	return true;
}


void CPGLImage::GetUnionExtent(gfxinterface::CGfxInterface& gfx, CPGLRectD& rExtent)
{
	if (NeedUpdateExtent())
		UpdateExtent(gfx);

	GetExtent().SetUnion(rExtent);

	rExtent.xValid=true;
	rExtent.yValid=true;
}

void CPGLImage::UpdateExtent(gfxinterface::CGfxInterface& gfx)
{
	SetExtent(m_area.GetWorldBBox(gfx));
}

void CPGLImage::PlotGfx(gfxinterface::CGfxInterface& gfx)
{
	using namespace Gdiplus;
	using namespace gfxinterface;

	if (!IsVisible())
		return;
	if (!IsInLayer(gfx.GetLayer()))
		return;
	if (!m_pBitmap)
		return;
	if (m_pBitmap->GetLastStatus() != Ok)
		return;

	// now we can draw....
	CPGLRectD rDestBitmapTemp = m_area.GetScreenBBox(gfx);

	SRectD rDestBitmap;
	rDestBitmap.left=rDestBitmapTemp.left; 	
	rDestBitmap.width=rDestBitmapTemp.GetWidth();
//	rDestBitmap.top=gfx.NormBBoxToBBy(0)-rDestBitmapTemp.top;	
	rDestBitmap.top=rDestBitmapTemp.top;	
	rDestBitmap.height=gfx.GetYDirectionUp()*rDestBitmapTemp.GetHeight();

	SRectI rOrigBitmap;
	rOrigBitmap.left=0; rOrigBitmap.width=m_pBitmap->GetWidth();
	rOrigBitmap.top=0;	rOrigBitmap.height=m_pBitmap->GetHeight();

	gfx.DrawBitmap(m_pBitmap, rOrigBitmap, rDestBitmap);
}

HBITMAP CPGLImage::GetHBITMAP()
{
	using namespace Gdiplus;

	if (m_eSourceType == SourceTypeNone)
		return NULL;

	HBITMAP hBitmap;
	Color bkg( (BYTE)floor(GetColor().GetRed()*255), (BYTE)floor(GetColor().GetGreen()*255), 
		(BYTE)floor(GetColor().GetBlue()*255));
	m_pBitmap->GetHBITMAP(bkg, &hBitmap);

	return hBitmap;
}
